package com.example.questionsystem.modules.qu.service.util;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.nodes.Node;
import org.jsoup.nodes.TextNode;
import org.jsoup.parser.Parser;
import org.jsoup.select.Elements;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class AdvancedContentExtractor2 {

    // 【题干】+数字+点
    private static final Pattern TITLE_WITH_NUMBER =
            Pattern.compile("【[^】]{1,60}】\\s*\\d+\\s*[\\.．]");

    // 【题型】（数字）
    private static final Pattern QUESTION_TYPE_WITH_NUMBER =
            Pattern.compile("【[^】]{1,60}】\\s*[（(]\\s*\\d+\\s*[）)]");

    // 数字+点 - 只匹配行首或段落开头的题目编号
    private static final Pattern NUMBER_WITH_DOT =
            Pattern.compile("^\\s*\\d+\\s*[\\.．]");
    // 滑窗长度上限
    private static final int MAX_WINDOW = 5;

    public static void main(String[] args) {
        // 测试用户提供的HTML（没有题目序号的情况）
        String userHtml = "<p class=\"1 DocDefaults \" style=\"position: relative; margin-left: 0.33in;text-indent: -0.33in;vertical-align: baseline;\"><span class=\"5 \" style=\"font-weight: bold;color: #000000;font-size: 12.0pt;\">【题干<span class=\"\" style=\"\">】</span><span class=\"\" style=\"font-family: 'Times New Roman';\">39</span></span><span class=\"5 \" style=\"color: #000000;font-size: 12.0pt;\">．上路距离均为</span><span class=\"5 \" style=\"color: #000000;font-size: 12.0pt;;font-family: 'Times New Roman';\">0.2km</span><span class=\"5 \" style=\"color: #000000;font-size: 12.0pt;\">。</span><span class=\"5 \" style=\"color: #000000;font-size: 12.0pt;\"><span class=\"\" style=\"\">每增运</span></span><span class=\"5 \" style=\"color: #000000;font-size: 12.0pt;;font-family: 'Times New Roman';\">0.5km</span><span class=\"5 \" style=\"color: #000000;font-size: 12.0pt;\">运输费用为</span><span class=\"5 \" style=\"color: #000000;font-size: 12.0pt;;font-family: 'Times New Roman';\">459</span><span class=\"5 \" style=\"color: #000000;font-size: 12.0pt;\">元</span><span class=\"5 \" style=\"color: #000000;font-size: 12.0pt;;font-family: 'Times New Roman';\">/1000m</span><span class=\"5 \" style=\"color: #000000;font-size: 12.0pt;vertical-align: super;font-size: smaller;;font-family: 'Times New Roman';\">3</span><span class=\"5 \" style=\"color: #000000;font-size: 12.0pt;\">。</span></p>";
        String s = extractContentHTML(userHtml);
        System.out.println(s);
    }
    public static String extractContentHTML(String html) {
        Document doc = Jsoup.parse(html);

        // 2. 处理段落内容
        Elements paragraphs = doc.select("p");
        for (Element p : paragraphs) {
            processParagraph2(p);

        }
       return removePStyles(doc.body().html());

    }
    public static String extractContentHTML2(String html) {
        Document doc = Jsoup.parse(html);

        // 1. 移除所有图片
        removeAllImages(doc);



        return doc.body().html();
    }

    /**
     * 递归处理元素（通常为 <p> 或其子元素）。
     * 主要思路：
     *  - 先在当前元素的直接子节点上做滑窗（长度到 MAX_WINDOW）拼接文本，寻找跨节点匹配。
     *  - 若匹配则删除覆盖该匹配的子节点（逐节点删除），然后重试（直到没有修改）。
     *  - 若没有跨节点匹配，则对单节点做常规替换或递归处理。
     */
    /**
     * 处理段落
     */
    private static void processParagraph2(Element element) {
        // 获取是否位于表格
        boolean inTable = isInsideTable(element);
        // p 段落的处理逻辑：
        if (element.tagName().equals("p")) {
            if (inTable) {
                // 表格内的段落：保留编号等数据，不做任何编号清理
                return;
            }
            // 非表格段落：去除段首“数字+点”组合
            if (removeNumberDotFromFirstSpan(element)) {
                return; // 如果成功处理了，就不再进行滑动窗口处理
            }
        }
        
        boolean modified;
        do {
            modified = false;

            List<Node> nodes = new ArrayList<>(element.childNodes());
            int n = nodes.size();

            outer:
            for (int i = 0; i < n; i++) {
                int maxJ = Math.min(n - 1, i + MAX_WINDOW - 1);

                for (int j = i; j <= maxJ; j++) {
                    String combined = combineText(nodes, i, j);

                    Matcher m1 = TITLE_WITH_NUMBER.matcher(combined);
                    Matcher m2 = QUESTION_TYPE_WITH_NUMBER.matcher(combined);
                    // 完全移除 NUMBER_WITH_DOT 的处理，避免误删内容中的数字+点

                    Matcher matcher = null;
                    if (m1.find()) matcher = m1;
                    else if (m2.find()) matcher = m2;

                    if (matcher != null) {
                        int end = matcher.end();
                        // 拿到最后一个节点
                        Node last = nodes.get(j);
                        String lastText = getNodeText(last);

                        // 把前缀删掉，只保留后半部分
                        String remain = combined.substring(end);

                        // 删除 i..j-1 的节点（但保留img标签）
                        for (int k = i; k < j; k++) {
                            Node node = nodes.get(k);
                            // 不删除img标签
                            if (node instanceof Element && ((Element) node).tagName().equals("img")) {
                                continue;
                            }
                            node.remove();
                        }

                        // 更新最后一个节点的文本为 remain
                        if (last instanceof TextNode) {
                            ((TextNode) last).text(remain);
                        } else if (last instanceof Element) {
                            Element lastElement = (Element) last;
                            // 保存img标签等非文本元素
                            Elements imgs = lastElement.select("img");
                            lastElement.empty();
                            if (!remain.isEmpty()) {
                                lastElement.appendText(remain);
                            }
                            // 重新添加img标签
                            for (Element img : imgs) {
                                lastElement.appendChild(img.clone());
                            }
                        }

                        modified = true;
                        break outer;
                    }
                }

                // 单节点递归 - 但不对span标签进行递归处理，避免误删内容中的数字+点
                Node node = nodes.get(i);
                if (node instanceof Element) {
                    Element nodeElement = (Element) node;
                    // 只对非span标签进行递归处理
                    if (!nodeElement.tagName().equals("span")) {
                        processParagraph2(nodeElement);
                    }
                    // 不删除img标签，即使它们没有文本内容
                    if (nodeElement.text().trim().isEmpty()
                            && !nodeElement.tagName().equalsIgnoreCase("img")
                            && nodeElement.select("img").isEmpty()) {
                        node.remove();
                        modified = true;
                        break;
                    }
                }
            }
        } while (modified);
    }

    /**
     * 专门处理开头的 span 标签中的数字+点组合
     * 支持三种情况：
     * 1. <span>1</span><span>.内容XX</span>
     * 2. <span>1.</span><span>内容XX</span>
     * 3. <span>1</span><span>.</span><span>内容XX</span>
     * @param element 要处理的元素
     * @return 如果处理了数字+点则返回 true，否则返回 false
     */
    private static boolean removeNumberDotFromFirstSpan(Element element) {
        Elements spans = element.select("span");
        if (spans.isEmpty()) {
            return false;
        }
        
        // 尝试从前几个 span 中组合出数字+点的模式
        StringBuilder combinedText = new StringBuilder();
        List<Element> spansToProcess = new ArrayList<>();
        
        // 最多检查前5个span，寻找数字+点的组合
        int maxSpansToCheck = Math.min(5, spans.size());
        
        for (int i = 0; i < maxSpansToCheck; i++) {
            Element span = spans.get(i);
            String spanText = span.text().trim();
            
            // 如果当前span为空，跳过
            if (spanText.isEmpty()) {
                spansToProcess.add(span);
                continue;
            }
            
            combinedText.append(spanText);
            spansToProcess.add(span);
            
            // 检查当前组合的文本是否匹配数字+点模式
            Matcher matcher = NUMBER_WITH_DOT.matcher(combinedText.toString());
            if (matcher.find()) {
                int end = matcher.end();
                String matchedPart = combinedText.substring(0, end);
                String remainPart = combinedText.substring(end);
                
                // 处理匹配的span们
                processMatchedSpans(spansToProcess, matchedPart, remainPart);
                return true;
            }
            
            // 如果当前组合已经超过了可能的数字+点长度，且没有匹配，则停止
            if (combinedText.length() > 10) {
                break;
            }
        }
        
        return false;
    }
    
    /**
     * 处理匹配到数字+点模式的span标签们
     * @param spansToProcess 需要处理的span列表
     * @param matchedPart 匹配的部分（数字+点）
     * @param remainPart 剩余的部分
     */
    private static void processMatchedSpans(List<Element> spansToProcess, String matchedPart, String remainPart) {
        // 删除所有匹配的span，除了最后一个
        for (int i = 0; i < spansToProcess.size() - 1; i++) {
            spansToProcess.get(i).remove();
        }
        
        // 处理最后一个span
        Element lastSpan = spansToProcess.get(spansToProcess.size() - 1);
        if (remainPart.trim().isEmpty()) {
            // 如果剩余内容为空，删除最后一个span
            lastSpan.remove();
        } else {
            // 保留剩余内容
            lastSpan.text(remainPart);
        }
    }

    /**
     * 拼接子节点的文本
     */
    private static String combineText(List<Node> nodes, int i, int j) {
        StringBuilder sb = new StringBuilder();
        for (int k = i; k <= j; k++) {
            sb.append(getNodeText(nodes.get(k)));
        }
        return sb.toString();
    }


    /**
     * 判断当前元素是否处在表格结构中（table/thead/tbody/tr/td/th 任一祖先）
     */
    private static boolean isInsideTable(Element element) {
        Element parent = element.parent();
        while (parent != null) {
            String tag = parent.tagName();
            if ("table".equalsIgnoreCase(tag)
                    || "thead".equalsIgnoreCase(tag)
                    || "tbody".equalsIgnoreCase(tag)
                    || "tr".equalsIgnoreCase(tag)
                    || "td".equalsIgnoreCase(tag)
                    || "th".equalsIgnoreCase(tag)) {
                return true;
            }
            parent = parent.parent();
        }
        return false;
    }

    private static String getNodeText(Node node) {
        if (node instanceof TextNode) {
            return ((TextNode) node).getWholeText();
        } else if (node instanceof Element) {
            Element element = (Element) node;
            // 对于img标签，返回占位符以防止被删除
            if (element.tagName().equalsIgnoreCase("img")) {
                return ""; // 图片不参与正则匹配
            }
            return element.text();
        }
        return "";
    }

    /**
     * 清除p标签中的特定CSS样式
     * 移除margin-left、text-indent和line-height: 95%样式
     * @param html 要处理的HTML字符串
     * @return 处理后的HTML字符串
     */
    public static String removePStyles(String html) {
        Document doc = Jsoup.parse(html);
        Elements paragraphs = doc.select("p");

        for (Element p : paragraphs) {
            String style = p.attr("style");
            if (style != null && !style.trim().isEmpty()) {
                // 移除margin-left样式
                style = removeStyleProperty(style, "margin-left");
                // 移除text-indent样式
                style = removeStyleProperty(style, "text-indent");
                // 移除line-height: 95%样式
                style = removeStyleProperty(style, "line-height", "95%");

                if (style.trim().isEmpty()) {
                    p.removeAttr("style");
                } else {
                    p.attr("style", style);
                }
            }
        }

        return doc.body().html();
    }
    /**
     * 清除p标签中的特定CSS样式
     * 移除margin-left、text-indent和line-height: 95%样式
     * @param html 要处理的HTML字符串
     * @return 处理后的HTML字符串
     */
    public static String removePStyles2(String html) {
        Document doc = Jsoup.parse(html);
        Elements paragraphs = doc.select("p");

        for (Element p : paragraphs) {
            String style = p.attr("style");
            if (style != null && !style.trim().isEmpty()) {

                // 移除text-indent样式
                style = removeStyleProperty(style, "text-indent");
                // 移除line-height: 95%样式
                style = removeStyleProperty(style, "line-height", "95%");

                if (style.trim().isEmpty()) {
                    p.removeAttr("style");
                } else {
                    p.attr("style", style);
                }
            }
        }

        return doc.body().html();
    }
    /**
     * 移除CSS样式属性
     * @param style 原始样式字符串
     * @param property 要移除的属性名
     * @return 移除后的样式字符串
     */
    private static String removeStyleProperty(String style, String property) {
        return removeStyleProperty(style, property, null);
    }
    /**
     * 移除CSS样式属性（可指定特定值）
     * @param style 原始样式字符串
     * @param property 要移除的属性名
     * @param specificValue 如果指定，只移除该特定值的属性
     * @return 移除后的样式字符串
     */
    private static String removeStyleProperty(String style, String property, String specificValue) {
        if (style == null || style.trim().isEmpty()) {
            return style;
        }

        // 分割样式属性
        String[] properties = style.split(";");
        StringBuilder result = new StringBuilder();

        for (String prop : properties) {
            String trimmedProp = prop.trim();
            if (trimmedProp.isEmpty()) {
                continue;
            }

            // 检查是否是要移除的属性
            if (trimmedProp.startsWith(property + ":")) {
                // 如果指定了特定值，检查是否匹配
                if (specificValue != null) {
                    String value = trimmedProp.substring(property.length() + 1).trim();
                    if (value.equals(specificValue)) {
                        continue; // 跳过这个属性
                    }
                } else {
                    continue; // 跳过这个属性
                }
            }

            // 保留其他属性
            if (result.length() > 0) {
                result.append("; ");
            }
            result.append(trimmedProp);
        }

        return result.toString();
    }

    /**
     * 删除一段连续节点
     */
    private static void removeNodes(List<Node> nodes, int i, int j) {
        for (int k = i; k <= j; k++) {
            Node node = nodes.get(k);
            // 不删除img标签
            if (node instanceof Element && ((Element) node).tagName().equals("img")) {
                continue;
            }
            node.remove();
        }
    }

    /**
     * 移除图片
     */
    private static void removeAllImages(Document doc) {
        Elements images = doc.select("img");
        for (Element img : images) {
            img.remove();
        }
    }



    private static String removeLeadingDot(Element element) {
        Element clone = element.clone();
        boolean dotRemoved = false;

        List<Node> childNodes = clone.childNodes();
        for (int i = 0; i < childNodes.size(); i++) {
            Node child = childNodes.get(i);

            if (child instanceof TextNode) {
                TextNode textNode = (TextNode) child;
                String text = textNode.getWholeText();
                String newText = removeLeadingDot(text);

                if (!newText.equals(text)) {
                    if (newText.isEmpty()) {
                        textNode.remove();
                    } else {
                        textNode.text(newText);
                    }
                    dotRemoved = true;
                    break;
                }
            }
            else if (child instanceof Element) {
                String newContent = removeLeadingDot((Element) child);
                if (!newContent.equals(((Element) child).outerHtml())) {
                    // 关键修复：使用parseFragment代替parse
                    List<Node> nodes = Parser.parseFragment(
                            newContent,
                            clone,
                            ""
                    );
                    if (!nodes.isEmpty()) {
                        child.replaceWith(nodes.get(0));
                    }
                    dotRemoved = true;
                    break;
                }
            }

            if (dotRemoved) break;
        }

        return clone.outerHtml();
    }

    private static String removeLeadingDot(String text) {
        // 只删除单独的点号，不删除数字+点的组合
        if (text.matches("^[．.,，]\\s*$")) {
            return "";
        }
        // 如果是单独的点号开头但后面还有其他内容，只删除点号
        if (text.matches("^[．.,，]\\s+.*")) {
            return text.replaceFirst("^[．.,，]\\s*", "").trim();
        }
        return text;
    }

}